home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 June: Reference Library / Dev.CD Jun 00 RL Disk 1.toast / pc / technical documentation / develop / develop issue 27 / develop issue 27 code / speech recognition.frameworks / cdocdemo w. speech / cdocspeech.cp < prev    next >
Encoding:
Text File  |  1996-06-28  |  13.1 KB  |  399 lines

  1. // ===========================================================================
  2. //    CDocSpeech.cp        C++ source code for speech recognition facilities
  3. // ===========================================================================
  4.  
  5. #include "CDocSpeech.h"
  6.  
  7. extern Boolean            gHasSpeechRecog;
  8.  
  9. //global variables
  10. SRRecognitionSystem        gSystem;
  11. SRRecognizer            gRecognizer;
  12. SRLanguageModel            gGApplLM;
  13. SRLanguageModel            gGDocuLM;
  14. SRPhrase                gRevert;
  15. CDocSpeech                *gDocSpeechObj = nil;        //the single instance of this class
  16.  
  17. //function prototypes
  18. void SetLanguageObjectState (SRLanguageObject inObj, Boolean isEnabled);
  19.  
  20. OSErr MyNewLanguageModel(ResIDT stringResource, short stringId, SRLanguageModel *theModel);
  21. OSErr MyNewPhrase(ResIDT stringResource, short stringId, SRPhrase *thePhrase);
  22. OSErr MyAddText(SRLanguageModel theModel, ResIDT stringResource, short stringId, long refCon);
  23.  
  24. // ===========================================================================
  25. //        • CDocSpeech Class
  26. // ===========================================================================
  27. // ---------------------------------------------------------------------------
  28. //        • CDocSpeech
  29. // ---------------------------------------------------------------------------
  30. //    Constructor
  31. //    Initialize speech recognition for this application.
  32.  
  33. CDocSpeech::CDocSpeech()
  34. {
  35.     OSErr    theErr = noErr;
  36.     
  37.         //open a recognition system
  38.     if (!theErr) {
  39.         theErr = ::SROpenRecognitionSystem(&gSystem, kSRDefaultRecognitionSystemID);
  40.     }
  41.     
  42.         //set recognition system properties
  43.         //we want the user-selected feedback and listening modes
  44.     if (!theErr) {
  45.         short theModes = kSRHasFeedbackHasListenModes;
  46.         theErr = ::SRSetProperty(gSystem, kSRFeedbackAndListeningModes, &theModes, sizeof(theModes));
  47.     }
  48.  
  49.         //create a recognizer with default speech source
  50.     if (!theErr)
  51.         theErr = ::SRNewRecognizer(gSystem, &gRecognizer, kSRDefaultSpeechSource);
  52.                         
  53.         //set recognizer properties
  54.         //we want to receive notifications when recognition begins and ends
  55.     if (!theErr) {
  56.         unsigned long theParam = kSRNotifyRecognitionBeginning | kSRNotifyRecognitionDone;
  57.         theErr = ::SRSetProperty(gRecognizer, kSRNotificationParam, &theParam, sizeof(theParam));
  58.     }
  59.  
  60.         //install AppleEvent handlers
  61.     if (!theErr) {
  62.         theErr = ::AEInstallEventHandler(kAESpeechSuite, kAESpeechDetected, NewAEEventHandlerProc(HandleSpeechBegunAppleEvent), 0, false);
  63.         theErr = ::AEInstallEventHandler(kAESpeechSuite, kAESpeechDone, NewAEEventHandlerProc(HandleSpeechDoneAppleEvent), 0, false);
  64.     }
  65.             
  66.         //make our language models
  67.     if (!theErr)
  68.         theErr = MakeLanguageModels();
  69.  
  70.         //install initial language model and release our reference to it
  71.     if (!theErr) {
  72.         theErr = ::SRSetLanguageModel(gRecognizer, gGApplLM);
  73.         ::SRReleaseObject(gGApplLM);
  74.     }
  75.  
  76.         //have the recognizer start processing sound
  77.     if (!theErr)
  78.         theErr = ::SRStartListening(gRecognizer);
  79.  
  80. }
  81.  
  82. // ---------------------------------------------------------------------------
  83. //        • ~CDocSpeech
  84. // ---------------------------------------------------------------------------
  85. //    Destructor
  86.  
  87. CDocSpeech::~CDocSpeech()
  88. {
  89.     ::SRStopListening(gRecognizer);
  90.     ::SRReleaseObject(gRecognizer);
  91.     ::SRReleaseObject(gGDocuLM);
  92.     ::SRReleaseObject(gRevert);
  93.     ::SRCloseRecognitionSystem(gSystem);
  94. }
  95.  
  96. // ---------------------------------------------------------------------------
  97. //        • MakeLanguageModels
  98. // ---------------------------------------------------------------------------
  99. //    Create the language models.
  100. //    We create one top-level language model, <gApplLM>.
  101. //    All other LMs are embedded language models.
  102. //
  103. //  Here is a BNF version of the models we want to create:
  104. //
  105. //    <Menu Commands> = <Universal Commands> | <Document Commands>
  106. //
  107. //    <Universal Commands> = <Universal Commands> | About DocDemo;
  108. //    <UFileLM> = New | Open | Page Setup | Quit;
  109. //    <Document Commands> = <Document File Commands> | <Document Edit Commands>;
  110. //    <Document File Commands> = Close | Save | Save As | Revert | Print | Print One;
  111. //  <Document Edit Commands> = Undo | Cut | ... | Clear | Select All;
  112. //
  113.  
  114. OSErr 
  115. CDocSpeech::MakeLanguageModels (void)
  116. {
  117.     OSErr                theErr = noErr;
  118.     SRLanguageModel        myGUnivLM;    // embedded language models
  119.     SRLanguageModel        myUFileLM;
  120.     SRLanguageModel        myDFileLM;
  121.     SRLanguageModel        myDEditLM;
  122.  
  123.     //make the language models [which are initially empty]
  124.     // The error handling is a bit repetitive, but necessary
  125.     if(!theErr)
  126.         theErr = MyNewLanguageModel(rSTR_LMNames, kStr_GApplLM, &gGApplLM);
  127.     if(!theErr)
  128.         theErr = MyNewLanguageModel(rSTR_LMNames, kStr_GUnivLM, &myGUnivLM);
  129.     if(!theErr)
  130.         theErr = MyNewLanguageModel(rSTR_LMNames, kStr_UFileLM, &myUFileLM);
  131.     if(!theErr)
  132.         theErr = MyNewLanguageModel(rSTR_LMNames, kStr_GDocuLM, &gGDocuLM);
  133.     if(!theErr)
  134.         theErr = MyNewLanguageModel(rSTR_LMNames, kStr_DFileLM, &myDFileLM);
  135.     if(!theErr)
  136.         theErr = MyNewLanguageModel(rSTR_LMNames, kStr_DEditLM, &myDEditLM);
  137.     
  138.     //make any other language objects we'll need
  139.     if(!theErr)
  140.         theErr = MyNewPhrase(kSTR_DFileCmds, kStr_Revert, &gRevert);
  141.             
  142.     
  143.     //****<Universal File Commands>****
  144.     if(!theErr)
  145.         theErr = MyAddText(myUFileLM, kSTR_UFileCmds, kStr_New, cmd_New);
  146.     if(!theErr)
  147.         theErr = MyAddText(myUFileLM, kSTR_UFileCmds, kStr_Open, cmd_Open);
  148.     if(!theErr)
  149.         theErr = MyAddText(myUFileLM, kSTR_UFileCmds, kStr_PageSetup, cmd_PageSetup);
  150.     if(!theErr)
  151.         theErr = MyAddText(myUFileLM, kSTR_UFileCmds, kStr_Quit, cmd_Quit);
  152.     //****<Universal File Commands>****
  153.     
  154.     //****<Document File Commands>****
  155.     if(!theErr)
  156.         theErr = MyAddText(myDFileLM, kSTR_DFileCmds, kStr_Close, cmd_Close);
  157.     if(!theErr)
  158.         theErr = MyAddText(myDFileLM, kSTR_DFileCmds, kStr_Save, cmd_Save);
  159.     if(!theErr)
  160.         theErr = MyAddText(myDFileLM, kSTR_DFileCmds, kStr_SaveAs, cmd_SaveAs);
  161.         
  162.     unsigned long theRefCon = cmd_Revert;
  163.     if(!theErr)
  164.         theErr = ::SRSetProperty(gRevert, kSRRefCon, &theRefCon, sizeof(theRefCon));
  165.     if(!theErr)
  166.         theErr = ::SRAddLanguageObject(myDFileLM, gRevert);
  167.     
  168.     if(!theErr)
  169.         theErr = MyAddText(myDFileLM, kSTR_DFileCmds, kStr_Print, cmd_Print);
  170.     if(!theErr)
  171.         theErr = MyAddText(myDFileLM, kSTR_DFileCmds, kStr_PrintOne, cmd_PrintOne);
  172.     //****<Document File Commands>****
  173.     
  174.     //****<Document Edit Commands>****
  175.     if(!theErr)
  176.         theErr = MyAddText(myDEditLM, kSTR_DEditCmds, kStr_Undo, cmd_Undo);
  177.     if(!theErr)
  178.         theErr = MyAddText(myDEditLM, kSTR_DEditCmds, kStr_Cut, cmd_Cut);
  179.     if(!theErr)
  180.         theErr = MyAddText(myDEditLM, kSTR_DEditCmds, kStr_Copy, cmd_Copy);
  181.     if(!theErr)
  182.         theErr = MyAddText(myDEditLM, kSTR_DEditCmds, kStr_Paste, cmd_Paste);
  183.     if(!theErr)
  184.         theErr = MyAddText(myDEditLM, kSTR_DEditCmds, kStr_Clear, cmd_Clear);
  185.     if(!theErr)
  186.         theErr = MyAddText(myDEditLM, kSTR_DEditCmds, kStr_SelectAll, cmd_SelectAll);
  187.     //****<Document Edit Commands>****
  188.  
  189.     //****<Document Commands>****
  190.     if(!theErr)
  191.         theErr = ::SRAddLanguageObject(gGDocuLM, myDFileLM);
  192.     if(!theErr)
  193.         theErr = ::SRAddLanguageObject(gGDocuLM, myDEditLM);
  194.     //****<Document Commands>****
  195.     
  196.     //****<Universal Commands>****
  197.     if(!theErr)
  198.         theErr = ::SRAddLanguageObject(myGUnivLM, myUFileLM);
  199.     if(!theErr)
  200.         MyAddText(myGUnivLM, kSTR_UApplCmds, kStr_About, cmd_About);
  201.     //****<Universal Commands>****
  202.  
  203.     // ****<Menu Commands>****
  204.     if(!theErr)
  205.         theErr = ::SRAddLanguageObject(gGApplLM, myGUnivLM);
  206.     if(!theErr)
  207.         theErr = ::SRAddLanguageObject(gGApplLM, gGDocuLM);
  208.     //****<Menu Commands>****
  209.  
  210.     // release any embedded language models we don’t need later
  211.     if(!theErr)
  212.     {
  213.         ::SRReleaseObject(myDFileLM);
  214.         ::SRReleaseObject(myUFileLM);
  215.         ::SRReleaseObject(myGUnivLM);
  216.     }
  217.  
  218.     return theErr;
  219.  
  220. }
  221.  
  222. // ---------------------------------------------------------------------------
  223. //        • HandleSpeechBegunAppleEvent
  224. // ---------------------------------------------------------------------------
  225. //    Handle recognition begun Apple event.
  226.  
  227. pascal OSErr 
  228. CDocSpeech::HandleSpeechBegunAppleEvent (AppleEvent *theAEevt, AppleEvent* reply, long refcon)
  229. {
  230. #pragma unused(reply, refcon)
  231.  
  232.     long                actualSize;
  233.     DescType            actualType;
  234.     OSErr                theErr = noErr, recStatus = noErr;
  235.     SRRecognizer        theRec;
  236.     LWindow                *theWindow;
  237.                 
  238.     //get status and recognizer
  239.     theErr = ::AEGetParamPtr(theAEevt, keySRSpeechStatus, typeShortInteger, &actualType, (Ptr)&recStatus, sizeof(recStatus), &actualSize);
  240.  
  241.     if (!theErr && !recStatus)
  242.         theErr = ::AEGetParamPtr(theAEevt, keySRRecognizer, typeSRRecognizer, &actualType, (Ptr)&theRec, sizeof(theRec), &actualSize);
  243.     
  244.     if(theErr)
  245.         if(!theRec) return theErr;
  246.         
  247.     //figure out what state we're in, then enable the appropriate language model
  248.     theWindow = UDesktop::FetchTopRegular();            //look for a document window
  249.     
  250.     if (theWindow != nil) {            //there is a document window open
  251.         //theErr = ::SRSetLanguageModel(gRecognizer, gGApplLM);
  252.         SetLanguageObjectState(gGDocuLM, kEnableObj);
  253.                                             
  254.         //make sure to turn off "Revert" if there's no file or it isn't dirty
  255.         //[notice the clever way we determine if Revert shoud be enabled!]
  256.         Boolean        isEnabled;
  257.         Boolean        outUsesMark;
  258.         Char16        outMark;
  259.         Str255        outName;
  260.             
  261.         LCommander::GetTarget()->FindCommandStatus(cmd_Revert, isEnabled, outUsesMark, outMark, outName);    
  262.         if (isEnabled)
  263.             SetLanguageObjectState(gRevert, kEnableObj);
  264.         else
  265.             SetLanguageObjectState(gRevert, kDisableObj);    
  266.         
  267.         // Similar gyrations with the edit menu should be done here
  268.             
  269.     } else {                        //there is no document window open
  270.         //theErr = ::SRSetLanguageModel(gRecognizer, gGApplLM);
  271.         SetLanguageObjectState(gGDocuLM, kDisableObj);
  272.     }
  273.     
  274.         //now tell the recognizer to continue
  275.     theErr = ::SRContinueRecognition(theRec);
  276.     return theErr;
  277. }
  278.  
  279. // ---------------------------------------------------------------------------
  280. //        • HandleSpeechDoneAppleEvent
  281. // ---------------------------------------------------------------------------
  282. //    Handle speech done Apple event.
  283. //    Here's our strategy: all commands are one item, which carries
  284. //    a unique refCon value. We extract the refCon and then pass it as a command to
  285. //    the current target.
  286.  
  287. pascal OSErr 
  288. CDocSpeech::HandleSpeechDoneAppleEvent (AppleEvent *theAEevt, AppleEvent* reply, long refcon)
  289. {
  290. #pragma unused(reply, refcon)
  291.  
  292.     long                actualSize;
  293.     DescType            actualType;
  294.     OSErr                theErr = 0, recStatus = 0;
  295.     SRRecognitionResult    recResult = nil;
  296.     Size                theLen;
  297.     SRPath                thePath;
  298.     SRSpeechObject        theItem;
  299.     long                theRefCon;    //refcon of item
  300.     
  301.         //get status
  302.     theErr = ::AEGetParamPtr(theAEevt, keySRSpeechStatus, typeShortInteger, &actualType, (Ptr)&recStatus, sizeof(theErr), &actualSize);
  303.  
  304.         //get result
  305.     if (!theErr && !recStatus)
  306.         theErr = ::AEGetParamPtr(theAEevt, keySRSpeechResult, typeSRSpeechResult, &actualType, (Ptr)&recResult, sizeof(SRRecognitionResult), &actualSize);
  307.                     
  308.         //get command from result by reading the refcon of the relevant object
  309.     if (!theErr && !recStatus) {
  310.         ::SRGetProperty(recResult, kSRPathFormat, &thePath, &theLen);
  311.         theErr = ::SRGetIndexedItem(thePath, &theItem, 0);
  312.         if (!theErr) {
  313.             theLen = sizeof(theRefCon);
  314.             ::SRGetProperty(theItem, kSRRefCon, &theRefCon, &theLen);            
  315.             ::SRReleaseObject(theItem);
  316.         }
  317.         //release recognition result, since we're done with it
  318.         ::SRReleaseObject(recResult);
  319.         ::SRReleaseObject(thePath);
  320.     }
  321.             
  322.     LCommander::GetTarget()->ObeyCommand((MessageT)theRefCon, nil);
  323.         
  324.     return theErr;
  325. }
  326.  
  327. // ---------------------------------------------------------------------------
  328. //        • SetLanguageObjectState
  329. // ---------------------------------------------------------------------------
  330. //    Enable or disable a language object. 
  331.  
  332. void SetLanguageObjectState (SRLanguageObject inObj, Boolean isEnabled)
  333. {
  334.     Boolean        theState = isEnabled;
  335.         
  336.     ::SRSetProperty(inObj, kSREnabled, &theState, sizeof(theState));
  337. }
  338.  
  339.  
  340. // These next few routines were added to make error handling a little cleaner
  341. // in MakeLanguageModels
  342.  
  343. // ---------------------------------------------------------------------------
  344. //        • MyNewLanguageModel
  345. // ---------------------------------------------------------------------------
  346. //    Make a new language model named with the given string. 
  347.  
  348. OSErr MyNewLanguageModel(ResIDT stringResource, short stringId, SRLanguageModel *theModel)
  349. {
  350.     Str255    theStr;
  351.     OSErr    theErr;
  352.     
  353.     ::GetIndString(theStr, stringResource, stringId);
  354.     if(theStr[0] == 0)
  355.         theErr = -1; // Signal error if empty string
  356.     else
  357.         theErr = ::SRNewLanguageModel(gSystem, theModel, &theStr[1], theStr[0]);
  358.  
  359.     return theErr;
  360. }
  361.  
  362. // ---------------------------------------------------------------------------
  363. //        • MyNewPhrase
  364. // ---------------------------------------------------------------------------
  365. //    Make a new phrase with the given string. 
  366.  
  367. OSErr MyNewPhrase(ResIDT stringResource, short stringId, SRPhrase *thePhrase)
  368. {
  369.     Str255    theStr;
  370.     OSErr    theErr;
  371.     
  372.     ::GetIndString(theStr, stringResource, stringId);
  373.     if(theStr[0] == 0)
  374.         theErr = -1; // Signal error if empty string
  375.     else
  376.         theErr = ::SRNewPhrase(gSystem, thePhrase, &theStr[1], theStr[0]);
  377.  
  378.     return theErr;
  379. }
  380.  
  381. // ---------------------------------------------------------------------------
  382. //        • MyAddText
  383. // ---------------------------------------------------------------------------
  384. //    Add the given string to the given language model with the given refcon. 
  385.  
  386. OSErr MyAddText(SRLanguageModel theModel, ResIDT stringResource, short stringId, long refCon)
  387. {
  388.     Str255    theStr;
  389.     OSErr    theErr;
  390.     
  391.     ::GetIndString(theStr, stringResource, stringId);
  392.     if(theStr[0] == 0)
  393.         theErr = -1; // Signal error if empty string
  394.     else
  395.         theErr = ::SRAddText(theModel, &theStr[1], theStr[0], refCon);
  396.  
  397.     return theErr;
  398. }
  399.